﻿#include"snack.h"
#define KEY_PRESSED(VK) ((GetAsyncKeyState(VK)&1) ? 1 : 0)

//设置光标的坐标
void SetPos(short x, short y)
{
	COORD pos = { x, y };
	//获取句柄
	HANDLE hOutput =  GetStdHandle(STD_OUTPUT_HANDLE);
	//设置标准输出上光标的位置为pos
	SetConsoleCursorPosition(hOutput, pos);
}


void snackinit(snacknode** snackhead)
{
	snacknode* temp = (snacknode*)malloc(sizeof(snacknode));
	if (temp == NULL)
	{
		printf("内存开辟失败\n");
		exit(1);
	}
	*snackhead = temp;
	temp->x = 24;//蛇头初始位置
	temp->y = 12;
	for (int i = 4; i > 0; i--)
	{
		temp->next = (snacknode*)malloc(sizeof(snacknode));
		if (temp->next == NULL)
		{
			printf("内存开辟失败\n");
			exit(1);
		}
		temp->next->y = temp->y;
		temp->next->x = temp->x - 2;
		temp->next->next = NULL;
		temp = temp->next;
	}
}

void printmap()//1~26格可活动
{
	SetPos(0, 0);
	int i = 0;
	for (i = 0; i <= 27; i++)//上框
	{
		printf("□");
	}
	for (i = 1; i <= 27; i++)//左
	{
		SetPos(0, i);
		printf("□");
	}
	for (i = 1; i < 27; i++)//下
	{
		printf("□");
	}
	for (i = 1; i <= 27; i++)//右
	{
		SetPos(54, i);
		printf("□");
	}

}

void printsnack(snacknode* snackhead)
{
	while (snackhead)//
	{
		SetPos(snackhead->x, snackhead->y);
		wprintf(L"●");
		snackhead = snackhead->next;
	}
}

snacknode* creatfood(snacknode* snackhead)
{

	snacknode* temp = snackhead;
	int x = (rand() % 26) * 2 + 2;
	int y = rand() % 26 + 1;
	int count = 0;
	while (temp)
	{
		if (count >= 26 * 26)//地图被填满
			return NULL;
		
		if (temp->x == x && temp->y == y)
		{
			x = (rand() % 26)*2+2;//1~51
			y = rand() % 26+1;
			count++;
			temp = snackhead;
			continue;
		}
		temp = temp->next;
	}
	SetPos(x, y);
	temp = (snacknode*)malloc(sizeof(snacknode));
	if (temp == NULL)
	{
		printf("内存开辟失败\n");
		exit(1);
	}
	temp->next = NULL;
	temp->x = x;
	temp->y = y;
	return temp;
}

void printnote()
{
	SetPos(59, 7);//打印操作说明
	printf("按下上，下，左，右键控制移动方向");
	SetPos(59, 10);
	printf("按下右shift加速,按下右ctrl减速");
	SetPos(59, 13);
	printf("速度越快得分越高");
	SetPos(59, 16);
	printf("Esc退出,q暂停");
	SetPos(59, 17);
	printf("不要撞到边界或者自己");
	SetPos(59, 19);
	printf("吃掉食物★以获得得分并加长");

}

//游戏准备阶段
snacknode* prepare()
{
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取句柄
	CONSOLE_CURSOR_INFO cursorinfo;
	GetConsoleCursorInfo(houtput, &cursorinfo);//获取光标信息，存入cursorinfo中
	cursorinfo.bVisible = false;//将光标改为不可见
	SetConsoleCursorInfo(houtput, &cursorinfo);//将设置好的光标信息由句柄进行应用
	
	SetPos(38, 12);//打印提示信息
	printf("欢迎来到贪吃蛇小游戏");
	SetPos(39, 22);
	system("pause");
	
	system("cls");//打印地图
	printmap();
	printnote();

	//创建蛇
	snacknode* snackhead = NULL;
	snackinit(&snackhead);

	printsnack(snackhead);//打印蛇

	SetPos(60, 27);
	system("pause");
	return snackhead;
	
}
struct parameter* parainit(snacknode* snackhead)
{
	struct parameter* para=(struct parameter*)malloc(sizeof(struct parameter));
	if (para == NULL)
	{
		printf("内存开辟失败\n");
		exit(1);
	}
	para->snackhead = snackhead;
	para->snackstaus = exsit;
	para->direction = right;
	para->speed = normal;//移速
	para->foodpointer = creatfood(para->snackhead);
	para->goal = 0;
	return para;
}

void move(struct parameter* para)
{
	//方向
	if (KEY_PRESSED(VK_UP) == 1)//上
		para->direction = up;
	else if (KEY_PRESSED(VK_DOWN) == 1)//下
		para->direction = down;
	else if (KEY_PRESSED(VK_LEFT) == 1)//左
		para->direction = left;
	else if (KEY_PRESSED(VK_RIGHT) == 1)//右
		para->direction = right;

	//移动蛇头
	int xtemp = para->snackhead->x;
	int ytemp = para->snackhead->y;
	bool dire = true;
	do
	{
		switch (para->direction)
		{
		case up:
			para->snackhead->y -= 1;
			if (para->snackhead->y == para->snackhead->next->y)//反向就改向
			{
				para->snackhead->y = ytemp;
				para->direction = down;
				dire = false;
			}
			else
				dire = true;
			break;
		case down:
			para->snackhead->y += 1;
			if (para->snackhead->y == para->snackhead->next->y)
			{
				para->snackhead->y = ytemp;
				para->direction = up;
				dire = false;
			}
			else
				dire = true;
			break;
		case left:
			para->snackhead->x -= 2;
			if (para->snackhead->x == para->snackhead->next->x)
			{
				para->snackhead->x = xtemp;
				para->direction = right;
				dire = false;
			}
			else
				dire = true;
			break;
		case right:
			para->snackhead->x += 2;
			if (para->snackhead->x == para->snackhead->next->x)
			{
				para->snackhead->x = xtemp;
				para->direction = left;
				dire = false;
			}
			else
				dire = true;
		}
	} while (dire == false);

	//蛇身跟上
	int xntemp = 0;
	int yntemp = 0;
	snacknode* ptemp = para->snackhead;
	while (ptemp->next)
	{
		xntemp = ptemp->next->x;
		yntemp = ptemp->next->y;
		ptemp->next->x = xtemp;
		ptemp->next->y = ytemp;
		xtemp = xntemp;
		ytemp = yntemp;
		ptemp = ptemp->next;
	}

	//速度
	if (KEY_PRESSED(VK_RCONTROL) == 1)//减速
	{
		switch (para->speed)
		{
		case fast:
			para->speed = normal;
			break;
		case normal:
			para->speed = slow;
		}
	}
	else if (KEY_PRESSED(VK_RSHIFT) == 1)//加速
	{
		switch (para->speed)
		{
		case slow:
			para->speed = normal;
			break;
		case normal:
			para->speed = fast;
		}
	}


}

void checkeat(struct parameter* para)
{
	if (para->snackhead->x == para->foodpointer->x && para->snackhead->y == para->foodpointer->y)//吃到了
	{
		snacknode* temp = para->snackhead;
		while (temp->next)//找尾
			temp = temp->next;
		temp->next = para->foodpointer;
		temp->next->x = temp->x;
		temp->next->y = temp->y;
		para->foodpointer = creatfood(para->snackhead);
		int t = 0;
		switch (para->speed)
		{
		case fast:
			t = 5;
			break;
		case normal:
			t = 3;
			break;
		case slow:
			t = 1;
		}
		para->goal += t;
	}
}

void checkexsit(struct parameter* para)
{
	if (para->snackhead->x == 0 || para->snackhead->x == 54 || para->snackhead->y == 0 || para->snackhead->y == 27)
	{
		para->snackstaus = killedbywall;
		return;
	}
	snacknode* temp = para->snackhead->next;
	while (temp)
	{
		if (temp->x == para->snackhead->x && temp->y == para->snackhead->y)
		{
			para->snackstaus = selfkilled;
			return;
		}
		temp = temp->next;
	}
}

void game(struct parameter* para)//游戏进行阶段
{
	do
	{
		Sleep(para->speed);//时停
		if (KEY_PRESSED(VK_ESCAPE) == 1)//按了Esc
			break;
		else if (KEY_PRESSED(0x51) == 1)//按了Q键
		{
			SetPos(60,27);
			system("pause");
			system("cls");
		}

		move(para);//移动
		checkeat(para);//判断吃+算分
		checkexsit(para);//死亡判断

		//刷新屏幕
		switch (para->snackstaus)
		{

		case killedbywall:
			SetPos(58, 26);
			printf("撞到墙了，游戏结束 ");
			system("pause");
			break;
		case selfkilled:
			SetPos(58, 30);
			printf("咬到自己了，游戏结束");
			system("pause");
			break;
		case exsit:
			system("cls");
			printsnack(para->snackhead);
			printmap();
			printnote();
			SetPos(para->foodpointer->x, para->foodpointer->y);
			wprintf(L"★");
			SetPos(60, 2);
			printf("得分：%d", para->goal);
		}
	}while (para->snackstaus == exsit);
}

void end(struct parameter** para)
{
	snacknode* temp = (*para)->snackhead->next;
	while (temp)
	{
		free((*para)->snackhead);
		(*para)->snackhead = temp;
		temp = temp->next;
	}
	free((*para)->snackhead);
	free((*para)->foodpointer);
	free(*para);
	*para = NULL;
}